import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Semaphore;
import java.util.logging.Logger;

/**
 * Simple implementation ObjectPool by using semaphores.
 *
 * public void printCheckout() is method for test (to see state of pool)
 * public T checkOut() throws InterruptedException is method for get object from pool
 * public void checkIn(T obj) is method for return object to pool
 * @author an.troitskaya
 */

public class MyObjectPool<T> {
    private List<T> objects;
    private int size;
    private static final Logger logger = Logger.getLogger(MyObjectPool.class.getName());
    private boolean[] checkedOut;
    private Semaphore available;
    public MyObjectPool(Class<T> classObject, int startSize) {
	    this.size = startSize;
	    objects = new ArrayList<T>(startSize);
        available = new Semaphore(size);
        checkedOut = new boolean[startSize];
	    for (int i  = 0; i < size; i++) {
            try {
                objects.add(classObject.newInstance());
            } catch (InstantiationException e) {
                Thread.currentThread().interrupt();
                logger.warning("InstantiationException in thread "+ Thread.currentThread().getName());
            } catch (IllegalAccessException e) {
                Thread.currentThread().interrupt();
                logger.warning("IllegalAccessException in thread "+ Thread.currentThread().getName());
            }
            checkedOut[i] = false;
        }
    }
    public T checkOut() throws InterruptedException {
        available.acquire();
        return getObject();
    }
    public void checkIn(T obj) {
        if (setObject(obj)) {
            available.release();
        }
    }

    private synchronized T getObject() {
        for (int i = 0; i < size; i++) {
            if (!(checkedOut[i])) {
                checkedOut[i] = true;
                return objects.get(i);
            }
        }
        return null;
    }
    private synchronized boolean setObject(T obj) {
        int index = objects.indexOf(obj);
        if (index == -1) {
           return false;
        }
        for (int i = 0; i < size; i++) {
           if (checkedOut[i]) {
               checkedOut[i] = false;
               return true;
           }
        }
       return false;
    }
    public synchronized void clearPool() {
        for (int i = 0; i < size; i++) {
            objects.remove(i);
        }
    }
    public void printCheckout() {
	    for (int i = 0; i < size; i++) {
		    logger.info(" "+checkedOut[i]);
	    }
    }
}
